package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	"github.com/urfave/cli"
)

const memoFile = "memos.txt" //用于存储备忘录的文件名

// 定义了三个命令：add用于添加备忘录，list用于查看所有备忘录，delete用于删除指定备忘录。备忘录数据存储在名为memos.txt的文件中。您可以根据需要修改文件名或使用数据库等其他存储方式。
/*
go run main.go

go run main.go add "Buy groceries"
go run main.go list
go run main.go delete 1
go run main.go list
*/

func main() {
	app := cli.NewApp()
	app.Name = "MemoApp"
	app.Usage = "A simple command line memo application"

	app.Commands = []cli.Command{
		//创建了一个新的命令行应用程序实例，并设置了应用程序的名称和用途
		{
			Name:    "add",
			Aliases: []string{"a"}, //命令的别名列表
			Usage:   "Add a new memo",
			Action: func(c *cli.Context) error {
				//go run main.go add Buy groceries这样的命令，那么add是命令的名称，Buy是第一个参数，groceries是第二个参数
				//使用c.Args().Get(0)来获取命令行中的第一个参数
				memo := c.Args().First() //从命令行参数中获取第一个参数作为备忘录内容
				if memo == "" {
					fmt.Println("Please provide a memo to add")
					return nil
				}
				err := addMemo(memo)
				if err != nil {
					fmt.Println("Error adding memo:", err)
				} else {
					fmt.Println("Memo added successfully")
				}
				return nil
			},
		},
		{
			Name:    "list",
			Aliases: []string{"l"},
			Usage:   "List all memos",
			Action: func(c *cli.Context) error {
				memos, err := listMemos()
				if err != nil {
					fmt.Println("Error listing memos:", err)
				} else {
					fmt.Println("All memos:")
					for i, memo := range memos {
						fmt.Printf("%d. %s\n", i+1, memo)
					}
				}
				return nil
			},
		},
		{
			Name:    "delete",
			Aliases: []string{"d"},
			Usage:   "Delete a memo",
			Action: func(c *cli.Context) error {
				index := c.Args().First() //获取要删除的备忘录的索引。
				if index == "" {
					fmt.Println("Please provide the index of the memo to delete")
					return nil
				}
				err := deleteMemo(index)
				if err != nil {
					fmt.Println("Error deleting memo:", err)
				} else {
					fmt.Println("Memo deleted successfully")
				}
				return nil
			},
		},
	}
	err := app.Run(os.Args)
	if err != nil {
		fmt.Println(err)
	}
	//因为这个包中是将命令行参数作为参数，并且传递到context中了
	//所以之后再调用前面定义的函数中的参数也需要使用context中的参数，所以不能用Scanner来接收参数调用函数。
	//scanner := bufio.NewScanner(os.Stdin)
	//for scanner.Scan() {
	//	line := scanner.Text()
	//	if line == "" {
	//		break
	//	}
	//	words := strings.Fields(line)
	//	err := app.Run(words)
	//	if err != nil {
	//		fmt.Println(err)
	//	}
	//}
}

func addMemo(memo string) error {
	//os.O_APPEND: 追加模式，表示在文件末尾写入数据，而不是覆盖已有内容。
	//os.O_WRONLY: 只写模式，表示以只写方式打开文件。
	//os.O_CREATE: 如果文件不存在，则创建文件。
	//0644 指文件所有者具有读写权限，而其他用户只有只读权限。
	file, err := os.OpenFile(memoFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		return err
	}
	defer file.Close()
	//fmt.Fprintf需要一个io.Writer接口类型的参数作为输出目标，所以第一个参数就是file
	_, err = fmt.Fprintf(file, "%s\n", memo)
	if err != nil {
		return err
	}

	return nil
}

func listMemos() ([]string, error) {
	file, err := os.Open(memoFile)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var memos []string
	//bufio.Scanner是一个用于逐行扫描数据的类型，可以方便地从文件中读取数据。
	scanner := bufio.NewScanner(file)
	//每次循环会调用scanner.Scan()方法来读取文件中的下一行数据
	for scanner.Scan() {
		memos = append(memos, scanner.Text()) //scanner.Text()方法会返回刚刚读取的一行数据
	}

	if err := scanner.Err(); err != nil {
		return nil, err
	}

	return memos, nil
}

func deleteMemo(indexStr string) error {
	file, err := os.OpenFile(memoFile, os.O_RDWR, 0644)
	if err != nil {
		return err
	}
	defer file.Close()

	index := indexStr
	memos, err := listMemos()
	if err != nil {
		return err
	}

	i := 0
	for i < len(memos) {
		if strings.TrimSpace(index) == fmt.Sprintf("%d", i+1) {
			memos = append(memos[:i], memos[i+1:]...)
			break
		}
		i++
	}

	file.Truncate(0)
	file.Seek(0, 0)

	for _, memo := range memos {
		_, err := fmt.Fprintf(file, "%s\n", memo)
		if err != nil {
			return err
		}
	}

	return nil
}
